# This file is part of Gehyra.
#
# Gehyra is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Gehyra is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Gehyra.  If not, see <http://www.gnu.org/licenses/>.

"""
@package gehyra.common.logger
Defines singleton Logger class to deal with all logging
$Id: logger.py 452 2011-01-21 13:40:28Z andyhhp@gmail.com $
"""

"""
@file gehyra/common/logger.py
Defines singleton Logger class to deal with all logging
"""

import sys, logging, logging.handlers
# import gehyra.common.util as util

class Logger(logging.getLoggerClass()):
    """Logger singleton class.
    Extends logging.getLoggerClass() to include a few extra useful functions
    """

    ## Singleton reference
    __instance = None

    ## Numeric level for logging packets
    PACKET = 15
    
    ## @var _has_file
    # @brief Boolean flag stating whether logging to a file has been set up
    
    @staticmethod
    def getInstance():
        """Static method returning the singleton instance.
        If no instance currently exists, the constructor is called, else the
        previously constructed instance is returned.  Can be called from a
        previous object if it exists.
        @code
        l = Logger.getInstance()
        o = l.getInstance()
        # both l and o refer to the same instance
        @endcode
        @returns Logger instance
        """
        if Logger.__instance == None:
            Logger()
        return Logger.__instance
    
    def __init__(self):
        """Constructor
        Multiple calls to the constructor will result in a RuntimeError.  The
        approved way of getting hold of the object is via the
        Logger.getInstance() static method.

        Creates a handler which writes to stdout
        @exception RuntimeError if called more than once
        @todo once initial development is complete, change logging level to
        normal and allow adjustment via the -v options
        """

        # Call superclass constructor to turn us into a logger
        logging.getLoggerClass().__init__(self, "gehyra", logging.DEBUG)
    
        # Raise exception if the an instance already exists
        if Logger.__instance != None:
            raise RuntimeError("Multiple calls to singleton constructor.  "
                               "Use Logger.getInstance() instead")
        Logger.__instance = self
        
        
        self._has_file = False
        
        # Create and add an IgnorentWriter as a handler
        stdout = logging.StreamHandler(_IgnorantWriter(sys.stdout))
        stdout.setLevel(logging.DEBUG)
        stdout.setFormatter(logging.Formatter("%(levelname).1s - %(message)s"))
        self.addHandler(stdout)

        # Add custom level for logging packets
        logging.addLevelName(Logger.PACKET, "PACKET")

        ## Dictionary of "packet type" -> bool detailing whether logging of
        ## certain packet types is enabled
        self.packet_enabled = {}
    
    def log_to_file(self, network_name):
        """Start logging to a file.
        Starts putting logging output into a file
        """
        
        # If the file has already been set, ignore this call
        if(self._has_file):
            return
            
        self._has_file = True
        
        # from gehyra.config.bridge_config import Bridge_Config as BC
        
        # if network_name is None or len(network_name) == 0:
        #     filename = ".log"
        # else:
        #     filename = "_" + network_name + ".log"
        
        # if BC.isBridgeNode:
        #     filename = "bridge" + filename
        #     max_size, max_archives = 4<<20, 4
        # else:
        #     filename = "network" + filename
        #     max_size, max_archives = 1<<20, 1
            
        # user_path = util.get_user_path(filename)

        # fh = logging.handlers.RotatingFileHandler(
        #     user_path, 'a', max_size, max_archives)
        # fh.setLevel(logging.DEBUG)
        # fh.setFormatter(logging.Formatter(
        #     "%(asctime)s - %(levelname).1s - %(message)s"))
        
        # self.addHandler(fh)
        
        # self.info("Started logging to %s" % filename)
        raise Exception("ToDO")


    def packet(self, src, line):
        """Log packet in a similar style to warn(), error() etc.
        Takes a packet source as well as a line as there are multiple
        possible of sources of packets to log which need to be distinguished,
        as well as individually enabled and disabled.
        @param src Packet type the line applies to
        @param line String containing the line to log
        """
        if src in self.packet_enabled and self.packet_enabled[src] is True:
            self.log(self.PACKET, line)

    def setPacketLogging(self, src, flag):
        """Enables or disables logging of a specified type of packet.
        This is independent of the current logging level.  E.G. to log
        ADC packets, logging level must be set to PACKET or lower, and
        ADC packets themselves must be enabled.
        @param src Packet type to modify
        @param flag Boolean specifying whether to enable or disable
        """
        self.packet_enabled[src] = flag

class _IgnorantWriter(object):
    """Wrapper around an output stream, which ignores IO Errors.
    """

    def __init__(self, stream = sys.stdout):
        """Constructor.
        @param stream Optional stream object, defaults to stdout
        """
        ## IO Stream
        self.stream = stream

    def write(self, data):
        """Write data.
        Calls stream.write and ignores any IOError exceptions
        @param data Data to write to the stream
        """
        try:
            r = self.stream.write(data)
            self.stream.flush()
            return r
        except IOError:
            pass
    
    def flush(self):
        """Flush.
        Calls stream.flush and ignores any IOError exceptions
        """
        try:
            return self.stream.flush()
        except IOError:
            pass

## @brief Global logging class for use by all modules
LOG = Logger.getInstance()

